package org.liaohailong.library.widget.interact.audio

import android.content.Context
import android.media.AudioManager
import android.media.MediaPlayer
import android.net.Uri
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.os.Message
import com.danikula.videocache.HttpProxyCacheServer
import java.lang.ref.WeakReference


/**
 * Author: liaohailong
 * Date: 2019/3/12
 * Time: 3:27 PM
 * Description:
 **/
object AudioPlayer : MediaPlayer.OnPreparedListener,
        MediaPlayer.OnCompletionListener,
        MediaPlayer.OnErrorListener {
    private var mediaPlayer: MediaPlayer? = null
    private val audioHandler: Handler

    private val audioPlayerObservers: MutableSet<OnAudioPlayerCallback> = mutableSetOf()
    private const val CREATE_MEDIA_PLAYER = 0
    private const val PLAY_MEDIA_PLAYER = 1
    private const val RELEASE_MEDIA_PLAYER = 2
    private const val RESET_MEDIA_PLAYER = 3

    private var contextHolder: WeakReference<Context>? = null
    private var currentUrl = ""
    private val mainHandler: Handler = Handler(Looper.getMainLooper())

    init {
        val handlerThread = HandlerThread("AudioPlayer")
        handlerThread.start()
        audioHandler = object : Handler(handlerThread.looper) {
            override fun handleMessage(msg: Message?) {
                msg?.let {
                    when (it.what) {
                        CREATE_MEDIA_PLAYER -> {
                            synchronized(this@AudioPlayer) {
                                if (mediaPlayer == null) {
                                    mediaPlayer = MediaPlayer.create(contextHolder!!.get(), Uri.parse(currentUrl)).apply {
                                        isLooping = false
                                        setAudioStreamType(AudioManager.STREAM_MUSIC)
                                        setOnPreparedListener(this@AudioPlayer)
                                        setOnCompletionListener(this@AudioPlayer)
                                        setOnErrorListener(this@AudioPlayer)
                                    }
                                }
                            }
                        }
                        PLAY_MEDIA_PLAYER -> {
                            mediaPlayer?.apply {
                                if (isPlaying) stop()
                                reset()
                                setDataSource(currentUrl)
                                prepareAsync()
                            }
                        }
                        RESET_MEDIA_PLAYER -> {
                            mediaPlayer?.apply {
                                if (isPlaying) stop()
                                reset()
                            }
                        }
                        RELEASE_MEDIA_PLAYER -> {
                            mediaPlayer?.apply {
                                if (isPlaying) stop()
                                release()
                                mediaPlayer = null
                            }
                        }
                        else -> {
                            //do nothing...
                        }
                    }
                }
            }
        }
    }

    private fun newProxy(context: Context): HttpProxyCacheServer {
        return HttpProxyCacheServer(context)
    }

    fun addAudioPlayerObserver(onAudioPlayerCallback: OnAudioPlayerCallback) {
        audioPlayerObservers.add(onAudioPlayerCallback)
    }

    fun removeAudioPlayerObserver(onAudioPlayerCallback: OnAudioPlayerCallback) {
        audioPlayerObservers.remove(onAudioPlayerCallback)
    }

    fun play(context: Context, url: String) {
        if (url.isEmpty()) return
        contextHolder = WeakReference(context)
        currentUrl = newProxy(context).getProxyUrl(url)

        if (mediaPlayer == null) {
            createMediaPlayer()
        } else {
            playMediaPlayer()
        }
    }

    private fun createMediaPlayer() {
        val message = Message.obtain()
        message.what = CREATE_MEDIA_PLAYER
        audioHandler.sendMessage(message)
    }

    private fun playMediaPlayer() {
        val message = Message.obtain()
        message.what = PLAY_MEDIA_PLAYER
        audioHandler.sendMessage(message)
    }

    fun resetMediaPlayer() {
        val message = Message.obtain()
        message.what = RESET_MEDIA_PLAYER
        audioHandler.sendMessage(message)
    }

    fun releaseMediaPlayer() {
        val message = Message.obtain()
        message.what = RELEASE_MEDIA_PLAYER
        audioHandler.sendMessage(message)
    }

    fun getTotalDuration(): Int {
        return mediaPlayer!!.duration
    }

    fun getCurrentPosition(): Int {
        return mediaPlayer!!.currentPosition
    }

    fun getAudioSession(): Int {
        return if (mediaPlayer == null) 0 else mediaPlayer!!.audioSessionId
    }

    override fun onPrepared(mp: MediaPlayer?) {
        mp?.start()
        mainHandler.post { for (observer in audioPlayerObservers) observer.onAudioPrepared() }
    }

    override fun onCompletion(mp: MediaPlayer?) {
        mainHandler.post { for (observer in audioPlayerObservers) observer.onAudioComplete() }
    }

    override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
        return false
    }

    interface OnAudioPlayerCallback {
        fun onAudioPrepared()
        fun onAudioComplete()
    }
}